#!/usr/bin/env python
# vim: set fileencoding=UTF-8

###############################################################################
#
# filename:  struct.py
#
# purpose:   Structure management for a config section
#
# author(s): Alessandro Molari (mola89.molarulez.com)
#            Luca Molari
#
# license:   This file is licensed under the GPLv2
#            For more informations read:
#            http://www.gnu.org/licenses/gpl-2.0.txt
#
# part of:   This file is part of the XazeInstaller
#
###############################################################################



"""
Structure management for a config section
"""



import shutil, os
import lxml.etree
import utils



class Structure:

    def __init__(self, init_space, struct, schema, configdir, currentuser):
        """
        Initialize the Structure management object
        Parameters:
            1- struct: Path of the xml file that contains the structure
            2- schema: Path of the XMLSchema file, used for the validation
                       of the struct file
            3- configdir: Path of the config section directory
            4- currentuser: Current logged in user
        """

        self.currentuser = currentuser

        self.fileinfo = utils.FileInfo(self.currentuser)
        
        # config section directory
        self.configdir = configdir

        # parse the input xml file 'schema' and build the parser
        #     to validate 'struct'
        xschema = lxml.etree.XMLSchema(lxml.etree.parse(schema))
        parser = lxml.etree.XMLParser(schema = xschema)

        # parse and validate 'struct' with the 'parser'
        self.struct_root = lxml.etree.parse(struct, parser)
        print "%s>>> Validated %s with %s" % (init_space, struct, schema)


    def __str__(self):
        return lxml.etree.tostring(self.struct_root)

    def __repr__(self):
        return repr(self.struct_root)


    def _clean_string(self, string, add_patterns=[]):
        """
        Remove from the input 'string' all of the characters in the
        patterns list.
        The pattern list is pre-built, but it can be extended with the
        optional list argument 'add_patterns'
        """

        # 'patterns' list contains all of the strings that will be removed
        #     from the input 'string'
        patterns = ["\a", "\b", "\f", "\n", "\t", "\v"]
        if len(add_patterns) > 0:
            patterns.extend(add_patterns)
        
        # remove from the input 'string' the matched elements in 'patterns'
        for pattern in patterns:
            string = string.replace(pattern, "")
        # remove all spaces
        string = string.replace(" ", "")
        
        return string


    def process(self, process_space):

        for item in self.struct_root.iterfind("//item"):

            # get the first 'svnpath' and 'localpath' on the top level
            #     from the current 'item'
            svnpath = item.find("./svnpath")
            localpath = item.find("./localpath")
            
            # fix 'svnpath'
            svnpath.text = os.path.abspath(os.path.join(self.configdir, \
                                             self._clean_string(svnpath.text)))
            
            # make sure 'svnpath' exists
            if not os.path.isfile(svnpath.text):
                raise IOError("%s doesn't exist" % (svnpath.text, ))

            # clean 'localpath'
            lp_cleaned = self._clean_string(localpath.text)
            
            # substitute current user home directory instead of #USERHOME#
            lp_list = lp_cleaned.split("/")
            for i in range(len(lp_list)):
                if lp_list[i] == "#USERHOME#":
                    if self.currentuser == "root":
                        lp_list[i] = "/root"
                    else:
                        lp_list[i] = os.path.join("/home", self.currentuser)
            lpath = "/".join(lp_list)
            
            # fix 'localpath'
            localpath.text = os.path.abspath(os.path.expandvars(lpath))

            # check 'localpath' make intermediate directories
            #     if they doesn't exist with the same owner and group
            #     as its file owner and group            
            lp_dirs = localpath.text.split("/")[1:-1]
            dir = "/"
            for lp_dir in lp_dirs:
                dir += "%s/" % (lp_dir, )
                if not os.path.isdir(dir):
                    os.mkdir(dir, 0755)
                    self.fileinfo.setup_owner(process_space, \
                                           dir, \
                                           lambda: localpath.attrib["owner"], \
                                           (KeyError, ))
                    self.fileinfo.setup_group(process_space, \
                                           dir, \
                                           lambda: localpath.attrib["group"], \
                                           (KeyError, ))

            # copy all files from 'svnpath' to 'localpath'
            shutil.copy(svnpath.text, localpath.text)
            print "%s>>> Copied %s in %s" % (process_space, \
                                             svnpath.text, \
                                             localpath.text)

            # setup permissions
            self.fileinfo.setup_permissions(process_space, \
                                   localpath.text, \
                                   lambda: int(localpath.attrib["perms"], 8), \
                                   (KeyError, ), \
                                   True)

            # setup owner
            self.fileinfo.setup_owner(process_space, \
                                      localpath.text, \
                                      lambda: localpath.attrib["owner"], \
                                      (KeyError, ), \
                                      True)

            # setup group
            self.fileinfo.setup_group(process_space, \
                                      localpath.text, \
                                      lambda: localpath.attrib["group"], \
                                      (KeyError, ), \
                                      True)




if __name__ == "__main__":
    print "struct executed"

